package com.qimu.saiyou.controller;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qimu.saiyou.annotation.AuthCheck;
import com.qimu.saiyou.common.BaseResponse;
import com.qimu.saiyou.common.DeleteRequest;
import com.qimu.saiyou.common.ErrorCode;
import com.qimu.saiyou.common.ResultUtils;
import com.qimu.saiyou.constant.UserConstant;
import com.qimu.saiyou.exception.BusinessException;
import com.qimu.saiyou.exception.ThrowUtils;
import com.qimu.saiyou.manager.RedisLimiterManager;
import com.qimu.saiyou.model.dto.question.QuestionAddRequest;
import com.qimu.saiyou.model.dto.question.QuestionQueryRequest;
import com.qimu.saiyou.model.dto.question.QuestionUpdateRequest;
import com.qimu.saiyou.model.entity.*;
import com.qimu.saiyou.model.enums.QuestionAnswerEnum;
import com.qimu.saiyou.model.enums.QuestionTypeEnum;
import com.qimu.saiyou.model.vo.QuestionVO;
import com.qimu.saiyou.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 题目
 *
 *@author: FeiXiang
 * 
 */
@RestController
@RequestMapping("/question")
@Slf4j
public class QuestionController {
    @Resource
    private QuestionBankRefService questionBankRefService;

    @Resource
    private QuestionBankService questionBankService;
    @Resource
    private QuestionService questionService;
    @Resource
    private QuestionAnswerService questionAnswerService;
    @Resource
    private UserService userService;
    @Resource
    private RedisLimiterManager redisLimiterManager;

    // region 增删改查

    /**
     * 创建
     *
     * @param request
     * @return
     */
    @PostMapping("/add")
    @Transactional(rollbackFor = Exception.class)
    @AuthCheck(anyRole = {"admin", "teacher"})
    public BaseResponse<Long> addQuestion(@RequestBody QuestionAddRequest questionAddRequest, HttpServletRequest request) {
        if (questionAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Question question = new Question();
        BeanUtils.copyProperties(questionAddRequest, question);
        questionService.validQuestion(question, true);
        if (questionAddRequest.getQuestionBankId() == null || questionAddRequest.getQuestionBankId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "题库不能为空");
        }
        QuestionBank questionBank = questionBankService.getById(questionAddRequest.getQuestionBankId());
        ThrowUtils.throwIf(questionBank == null, ErrorCode.NOT_FOUND_ERROR, "题库不存在");
        User loginUser = userService.getLoginUser(request);
        question.setUserId(loginUser.getId());
        List<QuestionAnswer> questionAnswerList = questionAddRequest.getQuestionAnswerList().stream().map(questionAnswerAddRequest -> {
            if (questionAnswerAddRequest == null) {
                return null;
            }
            QuestionAnswer questionAnswer = new QuestionAnswer();
            BeanUtils.copyProperties(questionAnswerAddRequest, questionAnswer);
            return questionAnswer;
        }).collect(Collectors.toList());
        if (CollUtil.isEmpty(questionAnswerList)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "答案不能为空");
        }
        boolean result = questionService.save(question);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        long newQuestionId = question.getId();

        checkQuestionAnswer(question, questionAnswerList);
        List<QuestionAnswer> answerArrayList = new ArrayList<>();
        for (QuestionAnswer questionAnswer : questionAnswerList) {
            questionAnswer.setQuestionId(newQuestionId);
            answerArrayList.add(questionAnswer);
        }
        questionAnswerService.saveBatch(answerArrayList);
        QuestionBankRef questionBankRef = new QuestionBankRef();
        questionBankRef.setQuestionId(question.getId());
        questionBankRef.setQuestionBankId(questionBank.getId());
        questionBankRefService.save(questionBankRef);

        return ResultUtils.success(newQuestionId);
    }

    private void checkQuestionAnswer(Question question, List<QuestionAnswer> questionAnswerList) {
        int trueCount = 0;
        for (QuestionAnswer questionAnswer : questionAnswerList) {
            if (StringUtils.isBlank(questionAnswer.getContent()) && !question.getType().equals(QuestionTypeEnum.SUBJECTIVE.getValue())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "答案内容不能为空");
            }
            // 是正确选项
            if (questionAnswer.getIsRight() != null && questionAnswer.getIsRight() == QuestionAnswerEnum.CORRECT.getValue()) {
                trueCount += 1;
            }
        }
        List<Integer> type = QuestionTypeEnum.getValues();
        if (!type.contains(question.getType())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "暂不支持该类型的题目");
        }
        if (trueCount == 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "至少要包含一个正确项");
        }
        // 单选题 判断
        if ((question.getType().equals(QuestionTypeEnum.RADIO.getValue())
                || question.getType().equals(QuestionTypeEnum.JUDGE.getValue()))
                && trueCount > 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "单选题或判断题不能包含多个正确项！");
        }
        if (question.getType().equals(QuestionTypeEnum.JUDGE.getValue())
                && questionAnswerList.size() > 2) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "判断题最多2个选项");
        }
    }

    /**
     * 删除
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    @AuthCheck(anyRole = {"admin", "teacher"})
    public BaseResponse<Boolean> deleteQuestion(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        long id = deleteRequest.getId();
        // 判断是否存在
        Question oldQuestion = questionService.getById(id);
        ThrowUtils.throwIf(oldQuestion == null, ErrorCode.NOT_FOUND_ERROR);

        QueryWrapper<QuestionAnswer> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().select(QuestionAnswer::getId).eq(QuestionAnswer::getQuestionId, oldQuestion.getId());
        List<Long> idsList = questionAnswerService.list(queryWrapper).stream().map(QuestionAnswer::getId).collect(Collectors.toList());
        questionAnswerService.removeByIds(idsList);
        boolean b = questionService.removeById(id);
        return ResultUtils.success(b);
    }

    /**
     * 更新（仅管理员）
     *
     * @param questionUpdateRequest
     * @return
     */
    @PostMapping("/update")
    @AuthCheck(anyRole = {"admin", "teacher"})
    @Transactional(rollbackFor = Exception.class)
    public BaseResponse<Boolean> updateQuestion(@RequestBody QuestionUpdateRequest questionUpdateRequest) {
        if (questionUpdateRequest == null || questionUpdateRequest.getId() == null || questionUpdateRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Question question = new Question();
        BeanUtils.copyProperties(questionUpdateRequest, question);
        // 参数校验
        questionService.validQuestion(question, false);
        // 判断是否存在
        Question oldQuestion = questionService.getById(questionUpdateRequest.getId());
        ThrowUtils.throwIf(oldQuestion == null, ErrorCode.NOT_FOUND_ERROR);
        if (ObjectUtils.anyNotNull(questionUpdateRequest.getQuestionAnswerList(), questionUpdateRequest.getType())) {
            if (CollUtil.isEmpty(questionUpdateRequest.getQuestionAnswerList())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "答案不能为空");
            }
            List<QuestionAnswer> questionAnswerList = questionUpdateRequest.getQuestionAnswerList().stream().map(questionAnswerAddRequest -> {
                if (questionAnswerAddRequest == null) {
                    return null;
                }
                QuestionAnswer questionAnswer = new QuestionAnswer();
                BeanUtils.copyProperties(questionAnswerAddRequest, questionAnswer);
                questionAnswer.setQuestionId(question.getId());
                questionAnswer.setId(null);
                return questionAnswer;
            }).collect(Collectors.toList());
            checkQuestionAnswer(question, questionAnswerList);
            questionAnswerService.lambdaUpdate().eq(QuestionAnswer::getQuestionId, question.getId()).remove();
            questionAnswerService.saveBatch(questionAnswerList);
        }
        boolean result = questionService.updateById(question);
        ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
        return ResultUtils.success(result);
    }

    /**
     * 根据 id 获取
     *
     * @param id
     * @return
     */
    @GetMapping("/get/vo")
    public BaseResponse<QuestionVO> getQuestionVOById(long id, HttpServletRequest request) {
        if (ObjectUtils.isEmpty(id) || id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Question question = questionService.getById(id);
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        return ResultUtils.success(questionService.getQuestionVO(question, request));
    }

    /**
     * 分页获取列表（仅管理员）
     *
     * @param questionQueryRequest
     * @return
     */
    @PostMapping("/list/page")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<QuestionVO>> listQuestionByPage(@RequestBody QuestionQueryRequest questionQueryRequest, HttpServletRequest request) {
        long current = questionQueryRequest.getCurrent();
        long size = questionQueryRequest.getPageSize();
        Page<Question> questionPage = questionService.page(new Page<>(current, size),
                questionService.getQueryWrapper(questionQueryRequest));
        return ResultUtils.success(questionService.getQuestionVOPage(questionPage, request));
    }

    /**
     * 分页获取列表（封装类）
     *
     * @param questionQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/list/page/vo")
    public BaseResponse<Page<QuestionVO>> listQuestionVOByPage(@RequestBody QuestionQueryRequest questionQueryRequest,
                                                               HttpServletRequest request) {
        long current = questionQueryRequest.getCurrent();
        long size = questionQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        Page<Question> questionPage = questionService.page(new Page<>(current, size),
                questionService.getQueryWrapper(questionQueryRequest));
        return ResultUtils.success(questionService.getQuestionVOPage(questionPage, request));
    }

    /**
     * 分页获取当前用户创建的资源列表
     *
     * @param questionQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<QuestionVO>> listMyQuestionVOByPage(@RequestBody QuestionQueryRequest questionQueryRequest,
                                                                 HttpServletRequest request) {
        if (questionQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        User loginUser = userService.getLoginUser(request);
        questionQueryRequest.setUserId(loginUser.getId());
        long current = questionQueryRequest.getCurrent();
        long size = questionQueryRequest.getPageSize();
        // 限制爬虫
        ThrowUtils.throwIf(size > 20, ErrorCode.PARAMS_ERROR);
        Page<Question> questionPage = questionService.page(new Page<>(current, size),
                questionService.getQueryWrapper(questionQueryRequest));
        return ResultUtils.success(questionService.getQuestionVOPage(questionPage, request));
    }

    // endregion

}
